﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Elderos.Utils.Extensions
{
	public static class LinqExtended
	{
		public static bool TryAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
												TKey key, TValue value, object locker = null)
		{
			if (locker == null)
				locker = new object();
			lock (locker)
			{
				if (dictionary.ContainsKey(key))
					return false;
				dictionary.Add(key, value);
				return true;
			}
		}

		public static bool AddRange<TKey, TValue>(this IDictionary<TKey, TValue> dictionary,
												  IEnumerable<KeyValuePair<TKey, TValue>> toAdd, object locker = null)
			where TKey : IEquatable<TKey>
		{
			if (locker == null) locker = new object();
			lock (locker)
			{
				if (dictionary.Any(x => toAdd.Any(y => x.Equals(y)))) return false;
				foreach (var kv in toAdd)
					dictionary.Add(kv);
				return true;
			}
		}

		public static void AddRange<T>(this HashSet<T> hashSet, IEnumerable<T> values)
		{
			foreach (var value in values)
			{
				hashSet.Add(value);
			}
		}

		public static bool TryAdd<TKey, TValue, TInnerValue>(this IDictionary<TKey, TValue> dictionary,
															 TKey key, TInnerValue value,
															 Action<TValue, TInnerValue> addFunction = null)
			where TValue : ICollection<TInnerValue>, new()
		{
			if (addFunction == null)
				addFunction = (x, y) => x.Add(y);
			
			if (dictionary.ContainsKey(key))
			{
				if (dictionary[key].Contains(value))
					return false;
			    
                addFunction.Invoke(dictionary[key], value);
			    return true;
			}
			dictionary.Add(key, new TValue());
			dictionary[key].Add(value);
			return true;
		}

		public static bool AddIfNotPresented<T>(this ICollection<T> collection, T value, object locker = null)
		{
			if (locker == null) locker = new object();
			lock (locker)
				if (!collection.Contains(value))
				{
					collection.Add(value);
					return true;
				}
			return false;
		}



		public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
		{
			foreach (T element in enumerable)
				action.Invoke(element);
		}

		public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable)
		{
			return enumerable == null || enumerable.Count() <= 0;
		}

		public static void Remove<TKey, TValue>(this Dictionary<TKey, TValue> dict, Predicate<KeyValuePair<TKey, TValue>> predicate)
		{
			TKey[] toRemove = dict.Where(predicate.Invoke)
								  .Select(x => x.Key)
								  .ToArray();
			foreach (TKey item in toRemove)
				dict.Remove(item);
		}
	}
}